package problems;

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

import utils.Utils;

public class Problem54 extends Problem<Integer> {
	private static final Set<Game> games = new HashSet<Game>();
	
	public static void main(String[] args) {
		Problem54 problem54 = new Problem54();
		problem54.runTimed();
		problem54.printResult();
	}

	@Override
	public void init() {
		Scanner scanner = Utils.getScannerForFile("poker.txt");
		scanner.useDelimiter("\\s+");
		while(scanner.hasNext()) {
			games.add(new Game(
					new Hand(scanner.next(), scanner.next(), scanner.next(), scanner.next(), scanner.next()),
					new Hand(scanner.next(), scanner.next(), scanner.next(), scanner.next(), scanner.next())
			));
		}
	}
	
	@Override
	public void run() {
		int p1 = 0;
		int p2 = 0;
		
		for (Game g : games) {
			if (g.player1wins()) {
				p1++;
			}
			else {
				p2++;
			}
		}
		setResult(p1);
	}
	
	private static class Game {
		private final Hand player1;
		private final Hand player2;

		public Game(Hand player1, Hand player2) {
			this.player1 = player1;
			this.player2 = player2;
		}
		
		boolean player1wins() {
			for (Card.Ranks rank : Card.Ranks.values()) {
				Card.Ranks.Result result = rank.compare(player1, player2);
				if (result == Card.Ranks.Result.UNDECIDED) {
					continue;
				}
				return result == Card.Ranks.Result.PLAYER1;
			}
			throw new IllegalStateException("No one wins: " + player1 + "; " + player2);
		}
	}

	private static class Hand {
		private final Set<Card> cards = new TreeSet<Card>();
		
		public Hand(String card1, String card2, String card3, String card4, String card5) {
			cards.add(new Card(Card.Suit.parse(card1), Card.Value.parse(card1)));
			cards.add(new Card(Card.Suit.parse(card2), Card.Value.parse(card2)));
			cards.add(new Card(Card.Suit.parse(card3), Card.Value.parse(card3)));
			cards.add(new Card(Card.Suit.parse(card4), Card.Value.parse(card4)));
			cards.add(new Card(Card.Suit.parse(card5), Card.Value.parse(card5)));
			
			System.out.println(this);
		}
		
		@Override
		public String toString() {
			return getClass().getSimpleName() + ": " + cards;
		}
	}
	
	private static class Card implements Comparable<Card> {
		public final Suit suit;
		public final Value value;

		public Card(Suit suit, Value value) {
			this.suit = suit;
			this.value = value;
		}
		
		@Override
		public String toString() {
			return value + " of " + suit;
		}
		
		@Override
		public int compareTo(Card other) {
			return suit.compareTo(other.suit) * 13 + value.compareTo(other.value);
		}
		
		public enum Suit {
			HEARTS,
			DIAMONDS,
			CLUBS,
			SPADES;
			
			public static Suit parse(String s) {
				switch(s.charAt(1)) {
					case 'H': return HEARTS;
					case 'S': return SPADES;
					case 'D': return DIAMONDS;
					case 'C': return CLUBS;
					default : throw new IllegalArgumentException(s);
				}
			}
		}
		
		public enum Value {
			ACE,
			TWO,
			THREE,
			FOUR,
			FIVE,
			SIX,
			SEVEN,
			EIGHT,
			NINE,
			TEN,
			JACK,
			QUEEN,
			KING;
			
			public static Value parse(String s) {
				switch(s.charAt(0)) {
					case 'J': return JACK;
					case 'Q': return QUEEN;
					case 'K': return KING;
					case 'A': return ACE;
					case 'T': return TEN;
					default : return values()[Integer.parseInt(s.substring(0, 1))-1]; 
				}
			}
		}
		
		public enum Ranks {
			STRAIGHT_FLUSH {
				@Override
				Result compare(Hand player1, Hand player2) {
					return Result.UNDECIDED;
				}
			},
			FOUR {
				@Override
				Result compare(Hand player1, Hand player2) {
					return Result.UNDECIDED;
				}
			},
			FULL_HOUSE {
				@Override
				Result compare(Hand player1, Hand player2) {
					return Result.UNDECIDED;
				}
			},
			FLUSH {
				@Override
				Result compare(Hand player1, Hand player2) {
					return Result.UNDECIDED;
				}
			},
			STRAIGHT {
				@Override
				Result compare(Hand player1, Hand player2) {
					return Result.UNDECIDED;
				}
			},
			THREE {
				@Override
				Result compare(Hand player1, Hand player2) {
					return Result.UNDECIDED;
				}
			},
			TWO_PAIRS {
				@Override
				Result compare(Hand player1, Hand player2) {
					return Result.UNDECIDED;
				}
			},
			ONE_PAIR {
				@Override
				Result compare(Hand player1, Hand player2) {
					return Result.UNDECIDED;
				}
			},
			HIGH_CARD {
				@Override
				Result compare(Hand player1, Hand player2) {
					return Result.UNDECIDED;
				}
			};
			
			abstract Result compare(Hand player1, Hand player2);
			
			enum Result {
				UNDECIDED,
				PLAYER1,
				PLAYER2
			}
		}
	}
}
